package org.lightrpc.server.http;

import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.lightrpc.LightRpcInitializationFailed;
import org.lightrpc.Response;
import org.lightrpc.server.FrontController;
import org.lightrpc.server.ServerFlowEngine;
import org.lightrpc.server.ServiceNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This servlet acts a front controller for all incoming http requests. Acts as
 * point of entry to the services and engine initialization, when using a
 * servlet to receive requests.
 * 
 * @author miku
 * 
 */
public class ServletFrontController extends HttpServlet implements
		FrontController {
	private static final Logger logger = LoggerFactory
			.getLogger(ServletFrontController.class);

	public static final String WEBSERVICES = "webservices";

	private static final long serialVersionUID = -7193902678345476059L;

	private ServerFlowEngine engine;

	private HttpServiceNameResolver serviceNameResolver;

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		// set defaults
		// resp.setContentType("text/json");
		// TODO:resolve the service name and the rootservicname
		// FIXME: this is done like shit currently!!!!!
		String[] uri = req.getRequestURI().split("/");
		try {
			if (uri.length >= 3) {
				// format the parameter map to a better format
				List<Object> params = new ArrayList<Object>();

				for (int i = 0; i < req.getParameterMap().values().size(); i++) {
					Object value = req.getParameter(String.valueOf(i));
					if (value == null) {
						throw new ServiceNotFoundException(
								"Illegal parameter names. Parameter name not found:"
										+ i);
					}
					params.add(i, value);
				}
				Response response = engine.incomingRpc(uri[1], uri[2], params);
				printResult(resp, response);

			} else {
				throw new ServiceNotFoundException("Illegal URL",
						new MalformedURLException());
			}
		} catch (Exception e) {
			printResult(resp, engine.formatException(e));
			// TODO add more specific error message
			logger.error("", e);
		}
	}

	private void printResult(HttpServletResponse resp, Response response)
			throws IOException {
		if (response.getStatus() == null
				|| response.getStatus().equals(Response.RPC_STATUS_SUCCESS))
			resp.setHeader(Response.RPC_STATUS_NAME,
					Response.RPC_STATUS_SUCCESS);
		else
			resp.setHeader(Response.RPC_STATUS_NAME,
					Response.RPC_STATUS_FAILURE);
		resp.getOutputStream().print(response.getData());
		resp.getOutputStream().flush();
		resp.getOutputStream().close();
	}
	
	/**
	 * Not yet testeed AT ALL!
	 */
	@Override
	public void init() throws ServletException {
		// there should be different ways to get the paths to the webservice
		// classes also, maybe init/prop file?
		ServletContext context = getServletContext();
		String inits = context.getInitParameter(WEBSERVICES);
		String[] classnames;
		if (inits == null || inits.isEmpty()) {
			classnames = (String[]) context.getAttribute(WEBSERVICES);
		} else {
			classnames = inits.split(",");
		}

		try {
			serviceNameResolver = new HttpServiceNameResolver();
			engine = new ServerFlowEngine(classnames, this, serviceNameResolver);
		} catch (LightRpcInitializationFailed e) {
			throw new ServletException(e);
		}
	}
}
